/*
 * Copyright (c) 2009, artur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * boot/arm/early.c
 * created: Sep 30, 2009
 *
 */

#include <sys/elf.h>
#include <sys/types.h>


typedef void (*kernel_entry_t)(unsigned long magic, unsigned long addr);

/**
 * Load and prepare kernel elf image
 * @param img Pointer to kernel ELF image in memory
 *
 */
void *
load_kernel_img(void *img)
{
	Elf32_Ehdr *e_hdr = NULL;
	Elf32_Phdr *p_hdr = NULL;
	Elf32_Shdr *s_hdr = NULL;
	char *dst= NULL, *src=NULL;
	size_t k=0,n=0;
	int i=0;
	/* void (*k_entry)(unsigned long magic, unsigned long addr) = NULL; */
	kernel_entry_t *k_entry = NULL;

	if (!img) return;

	e_hdr = (Elf32_Ehdr *)img;
  	p_hdr = (Elf32_Phdr *)((vaddr_t)e_hdr + e_hdr->e_phoff);
 	s_hdr = (Elf32_Shdr *)((vaddr_t)e_hdr + e_hdr->e_shoff);
 	k_entry = (kernel_entry_t *)e_hdr->e_entry;

 	s_hdr = (Elf32_Shdr *)((vaddr_t)e_hdr + e_hdr->e_shoff);

 	for (i=0;i<(int)e_hdr->e_shnum; i++, s_hdr++)
 	{
 		if (s_hdr->sh_addr && s_hdr->sh_size > 0) {
 			/* for NOBITS sections */
 			if (s_hdr->sh_type == SHT_NOBITS) {
 				continue;
 			}
 			else
 			{
				dst = (char *)s_hdr->sh_addr;
 				src = (char *)((int)img + (int)s_hdr->sh_offset);
 				n = s_hdr->sh_size;
 				for (k = 0; k<n; k++) {
 					dst[k] = src[k];
 				}
 			}
 		}
	}

 	return (void *)k_entry;
}
